package com.juc.concurrency.jucExample.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 只执行5秒，观察输出结果，20个线程 不会都执行完 会执行3*5=15个
 * 有参方法tryAcquire（int permits，long timeout，TimeUnit unit）的作用是在指定的时间timeout内尝试地获得permits个许可，
 * 如果获取不到则返回false。
 * 例如semaphore.tryAcquire(2,2, TimeUnit.SECONDS)表示2秒内获取2个许可，获取不到则返回false
 */
@Slf4j
public class SemaphoreExample4 {

    private final static int threadCount = 20;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final Semaphore semaphore = new Semaphore(3);

        //tryAcquire通过参数指定了5秒的等待时间。 上述代码中同一时间最多执行3个。
        // 第4个线程因前3个线程执行需要耗时一秒未释放许可，因此需要等待。 但是由于设置了5秒的等待时间，
        // 所以在5秒内等待到了释放的许可，继续执行，循环往复。但是20个线程
        // ，每秒并发3个，5S是执行不完的。
        // 所以上面执行到第16个（0开始，显示是15）就结束了，【每次执行结果会有差异，取决于CPU】，并没有全部执行完20个线程。
        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            exec.execute(() -> {
                try {
                    if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) { // 尝试获取一个许可
                        test(threadNum);
                        semaphore.release(); // 释放一个许可
                    }
                } catch (Exception e) {
                    log.error("exception", e);
                }
            });
        }
        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        log.info("{}", threadNum);
        Thread.sleep(1000);
    }
}
